<?php
/**
 * Mapper générique
 * 
 * @package bp-clients
 */
 
/**
 * Mapper générique
 * 
 * fournit les méthodes de bases d'un mapper
 * 
 * @package bp-clients
 */
abstract class Application_Model_MapperAbstract
{
	/**
	 * Objet Table liée
	 * @var Zend_Db_Table_Abstract
	 */
    static protected $_dbTable;
    
	/**
	 * Constructeur
	 */
    public function __construct() {
    	$classeDb = static::getNomClasseTable();
        $this->_dbTable = new $classeDb();
    }
	
    
	/**
	 * Sauvegarde un modele dans la base
	 * @param Application_Model_ModelAbstract $model Le model a sauvegarder
	 * @return int l'identifiant du modèle sauvegardé
	 */
	public function save(Application_Model_ModelAbstract $model)
    {       
        $data = $this->mapToDbDataArray($model);
        if (0 === ($id = $model->getId())) {
            $id = $this->_dbTable->insert($data);
        } else {
        	$nomTable = get_class($this->_dbTable);
			$where = $this->_dbTable->getAdapter()->quoteInto($nomTable::COL_ID . ' = ?', $id);
			$this->_dbTable->update($data, $where);
        }
        return $id;
    }
	
	/**
	 * Lit un model depuis la base
	 * @param int $id l'identifiant du model
	 * @return Application_Model_ModelAbstract le model completé
	 * @throws Zend_Exception Si le model est inconnu dans la base 
	 */
    public function findById($id)
    {
        $result = $this->_dbTable->find($id);
        if (0 == count($result)) {
            throw new Zend_Exception("Enregistrement inconnu");
        }
        $row = $result->current();
        
        return $this->mapToModelObject($row);
    }

    /**
     * Renvoie un tableau de tout les models
     * @param string $triCol le nom de la colonne de tri
     * @param string $triDir 'ASC' ou 'DESC', le sens de tri
     * @return array le tableau de tout les models
     */
    public function fetchAll($triCol='', $triDir='ASC')
    {
        $rows = $this->_dbTable->fetchAll($this->selectOrder($triCol, $triDir));
        return $this->mapToModelArray($rows);
    }

    /**
     * Prépare une requete select
     * @param string $triCol le nom de la colonne de tri
     * @param string $triDir 'ASC' ou 'DESC', le sens de tri
     * @return Zend_Db_Table_Select
     */
    protected function selectOrder($triCol='', $triDir='ASC'){
        $orderBy = $this->nameObjectToField($triCol)
                   . ' ' 
                   . $triDir;
        $select = $this->_dbTable->select()
                                 ->order($orderBy); 
        return $select; 
    }
	
	/**
	 * Transforme un enregistrement de table vers un model
	 * @param Zend_Db_Table_Row_Abstract $row l'enregistrement de la base de données
	 * @return Application_Model_ModelAbstract Le model transformé
	 */
    protected function mapToModelObject(Zend_Db_Table_Row_Abstract $row, Application_Model_ModelAbstract $model=null)
    {
    	$classeModel = static::getNomClasseModel(); 	
    	if (!$model){
    	    $model = $this->newModel();
        }
    	foreach ($model->getNomAttributs() as $nomAttribut) {
			$methode = 'set' . ucfirst($nomAttribut);
			$classeDb = $this->getNomClasseTable();
			$colonne = 'COL_' . strtoupper($nomAttribut);
			$champ = constant("$classeDb::$colonne");
			$model->$methode($row->$champ);
		}
        return $model;
    } 
	
	/**
	 * Convertit le nom d'un attribut d'un model vers le nom de la colonne SQL
	 * @param string name le nom de l'attribut
	 * @return string le nom de la colonne
	 */
	public function nameObjectToField($name){
		$classeDb = $this->getNomClasseTable();
		$colonne = 'COL_' . strtoupper($name);
		return constant("$classeDb::$colonne");
    }

	/**
	 * Transforme un model en un tableau de colonnes SQL => valeur
	 * @param Application_Model_ModelAbstract $model le model a transformer
	 * @return array le tableau de valeurs
	 */
    protected function mapToDbDataArray(Application_Model_ModelAbstract $model)
    {
        $data = array();
    	foreach ($model->getNomAttributs() as $nomAttribut) {
			$methode = 'get' . ucfirst($nomAttribut);
			$classeDb = $this->getNomClasseTable();
			$colonne = 'COL_' . strtoupper($nomAttribut);
			$champ = constant("$classeDb::$colonne");
			$data[$champ] = $model->$methode();
		}
        return $data;
    }
        
    /**
	 * Transforme un tableau de colonnesSQL => valeurs en un tableau de model
	 * @param Zend_Db_Table_Rowset_Abstract $rows le tableau de valeurs
	 * @return array le tableau de model
	 */
    public function mapToModelArray(Zend_Db_Table_Rowset_Abstract $rows) {        
        $entries   = array();
        foreach ($rows as $row) {           
            $entries[] = $this->mapToModelObject($row);
        }
        return $entries;
    }
    
    /**
     * Renvoie un nouveau model vierge
     * @param array $attributs
     * @return Application_Model_ModelAbstract
     */    
    public function newModel(array $attributs = null){
        $modelClasse = $this->getNomClasseModel();    
        return new $modelClasse($this, $attributs);
    }
}
